package edu.ccut.saturn.component.impl.directory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

import edu.ccut.saturn.component.IDirectoryInfo;
import edu.ccut.saturn.component.ILogger;
import edu.ccut.saturn.component.SaturnComponentException;
import edu.ccut.saturn.component.SaturnLoggerManager;
import edu.ccut.saturn.component.utils.LoaderUtils;

/**
 * 根据属性文件生成<code>IDirectoryInfo</code>类型实例的单态工厂类。
 * 属性文件中记录了路径资源的类型及对应的实现类。如果增加或减少了现有的路径资源的类型需要相应的改变属性文件的内容。
 * 
 * @author 谷钰
 * 
 * @version 1.0 2008.8.29
 * 
 */
public class SaturnDirectoryFactory {

	private static final String DIRECTORY_TYPE_FILE_NAME = "directory_type.properties";

	protected static ILogger logger = SaturnLoggerManager.getInstance()
			.getSaturnLogger(SaturnLoggerManager.LOGGER_KEY_LOAD_BUNDLE);

	private static SaturnDirectoryFactory instance;

	static {
		instance = new SaturnDirectoryFactory();
	}

	private Map<String, Class<?>> directoryClassMap;

	private SaturnDirectoryFactory() {
		loadDirectoryClass();
	}

	/**
	 * 获得<code>SaturnDirectoryFactory</code>的单态实例
	 * 
	 * @return
	 */
	public static SaturnDirectoryFactory getInstance() {
		return instance;
	}

	/**
	 * 创建路径资源实例的方法。根据传入的参数type判断要创建哪种类型的路径资源实例。
	 * 
	 * @param version
	 *            待创建的路径资源实例的版本信息
	 * @param description
	 *            待创建的路径资源实例的描述信息
	 * @param type
	 *            待创建的路径资源实例的类型信息
	 * @param time
	 *            待创建的路径资源实例的创建时间
	 * @return
	 * @throws SaturnComponentException
	 */
	public IDirectoryInfo createDirectory(String version, String description,
			String type, String time) throws SaturnComponentException {

		try {

			if (this.directoryClassMap.containsKey(type)) {
				Class<?> directoryClass = this.directoryClassMap.get(type);

				IDirectoryInfo directoryInfo = (IDirectoryInfo) directoryClass
						.newInstance();

				directoryInfo.setVersion(version);
				directoryInfo.setDescription(description);
				directoryInfo.setTime(time);
				return directoryInfo;
			}

		} catch (InstantiationException e) {
			e.printStackTrace();

		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		// throw new SaturnComponentException("the directory type : " + type
		// + " is not valid");
		return null;
	}

	@SuppressWarnings("unchecked")
	private void loadDirectoryClass() {
		Properties properties = new Properties();
		InputStream in = null;
		this.directoryClassMap = new HashMap<String, Class<?>>();

		try {
			in = SaturnDirectoryFactory.class
					.getResourceAsStream(DIRECTORY_TYPE_FILE_NAME);
			if (in == null) {
				// 如果不存在配置文件directory_type.properties, 生成默认配置
				logger
						.warn("can't find edu/ccut/saturn/component/impl/directoryLoad/directory_type.properties, load directoryClass defaultly.");
				this.directoryClassMap.put("web", SaturnWebDirectoryInfo.class);
				this.directoryClassMap.put("action",
						SaturnActionDirectoryInfo.class);
				this.directoryClassMap.put("logic",
						SaturnLogicDirectoryInfo.class);
				this.directoryClassMap.put("component",
						SaturnBaseComponentDirectoryInfo.class);
				this.directoryClassMap
						.put("data", SaturnDataDirectoryInfo.class);
				this.directoryClassMap.put("validate",
						SaturnValidateDirectoryInfo.class);
				this.directoryClassMap.put("workflow",
						SaturnWorkFlowDirectoryInfo.class);
				this.directoryClassMap.put("module",
						SaturnModuleDirectoryInfo.class);
			} else {
				properties.load(in);
				for (Enumeration propertyNames = properties.propertyNames(); propertyNames
						.hasMoreElements();) {

					String key = (String) propertyNames.nextElement();
					String className = properties.getProperty(key);

					this.directoryClassMap.put(key, LoaderUtils.loadClass(className));
				}
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (in != null) {
				try {
					in.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}

	}
}
